﻿#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

class ShallowSymantic{

	static const SQLBIGINT undefinedId = -1;

public:
	// Направления отношений для объектов ( Левое, Правое и Любое )
	enum RelationDirection{
		RelationLeft,
		RelationRight,
		RelationAny
	};

	ShallowSymantic();	//Конструктор
	~ShallowSymantic();	//Деструктор
	bool connect(const std::wstring &database,
		const std::wstring &user,
		const std::wstring &password);
	bool disconnect();
	
	std::vector< std::wstring > parseObject( SQLBIGINT objId );
	std::vector< std::wstring > parseChain( const std::vector<SQLBIGINT> & chain );

	/*
	 *	Поиск отношений между объектами в определенном направлении.
	 *	dir - задает направление поиска (Слева на право, справа на лево или любое);
	 *	если не задан targetObjId, то поиск ведется по всем направлениям и отыскиваются все возможные
	 *	связи для rootObjId;
	 *	если targetObjId задан, то поиск ведется до тех пор пока не будет обнаружен путь из rootObjId
	 *	до targetObjId, возвращаемое значение в таком случае будет путем.
	 */
	std::vector< SQLBIGINT > searchRelations(
		SQLBIGINT rootObjId,
		RelationDirection dir,
		SQLBIGINT targetObjId = undefinedId);

	void test();
private:
	SQLHENV env;	//Дескриптор окружения
	SQLHDBC conn;	//Дескриптор соединения
	SQLRETURN ret;	//Переменная, используемая в качестве	
					//возвращаемого значения

	//Структура объектов
	struct ObjectsRow{		
		SQLBIGINT id;
		SQLBIGINT upObjId;
		SQLINTEGER fullLenCnt;
		SQLINTEGER partLenCnt;
		SQLSMALLINT root;
	};

	//Структура графем
	struct GraphemasRow{	
		SQLBIGINT id;
		SQLBIGINT ownerId;
		std::wstring graphema;
		SQLINTEGER attributeMode;
	};

	//Структура нормальных форм графем
	struct GraphemaNormalFormsRow{	
		SQLBIGINT id;
		SQLBIGINT graphId;
		std::wstring normalForm;
		SQLINTEGER CID;
		SQLINTEGER VID;
	};

	//Структура атрибутов
	struct AttributesRow{	
		SQLBIGINT id;
		std::wstring objId;
		SQLSMALLINT type;
	};

	//Структура модификаторов
	struct AttributeModifiersRow{
		SQLBIGINT id;
		SQLINTEGER atrId;
	};

	//Структура отношений
	struct IssRelationsRow{
		SQLBIGINT id;
		SQLBIGINT fromObjId;
		SQLBIGINT toObjId;
		SQLINTEGER type;
		SQLBIGINT cnt;
		SQLDOUBLE possibility;
	};

	//Структура расположения
	struct PlacementRow{	
		SQLBIGINT id;
		std::wstring placement;
		SQLBIGINT type;
	};




	//Получаем строку из таблицы objects
	bool getObjectsRow( SQLBIGINT id, ObjectsRow * result );

	//Получаем строку из таблицы graphemas
	std::vector<GraphemasRow> getGraphemasRow( SQLBIGINT id );

	//Получаем строку из таблицы graphemaNormalForms
	bool getGraphemaNormalFormsRow( SQLBIGINT id, GraphemaNormalFormsRow * result );

	//Получаем строку из таблицы attributes
	std::vector<AttributesRow> getAttributesRow( SQLBIGINT id );

	//Получаем строку из таблицы placement
	std::vector<PlacementRow> getPlacementsRow( SQLBIGINT id );
	
	//Получаем отношения для объектов
	std::vector<IssRelationsRow> getRelation( SQLBIGINT id, RelationDirection dir );
	bool getRelation( SQLBIGINT fromObjId, SQLBIGINT toObjId, IssRelationsRow * result );

	//Поиск всех возможных объектов связанных напрямую или косвенно с объектом rootObjId
	std::vector<SQLBIGINT> search( SQLBIGINT rootObjId, RelationDirection dir );
	
	//Поиск наименьшей цепочки связей между объектами rootObjId и targetObjId
	std::vector<SQLBIGINT> searchPath( SQLBIGINT rootObjId, SQLBIGINT targetObjId, RelationDirection dir );

	/*	
	 *	Получаем текстовое поле из таблицы.
	 *	Вызывается после SQLFetch для запроса query_stmt,
	 *	rowNum - номер столбца, где содержится текстовое поле.
	 */
	std::wstring retrieveTextField(SQLHSTMT query_stmt, SQLUSMALLINT rowNum);
	
};